﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace eslib.nnp5.Tools
{
    /// <summary>
    /// 连接token管理器
    /// </summary>
    public class ConnectionTokenManager
    {

        /// <summary>
        /// 
        /// </summary>
        /// <param name="expireSeconds">token的过期时间(秒数)</param>
        /// <param name="guidLens">使用的Guid长度个数，默认为1</param>
        public ConnectionTokenManager(int expireSeconds = 1200, int guidLens = 1)
        {
            this.expireSeconds = expireSeconds;
            this.guidLens = guidLens;
        }



        /// <summary>
        /// 创建新Token，并加入token表
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ConnectionToken NewToken(int id) => NewToken(id);


        /// <summary>
        /// 创建新Token，并加入token表
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public ConnectionToken NewToken(long id)
        {
            ConnectionToken token = new ConnectionToken()
            {
                ID = id,
                UUID = NewUUID(guidLens),
                ExpireTime = NewExpireTime()
            };

            lock (this)
            {
                tokenTable[token.UUID] = token;
            }
            return token;
        }



        /// <summary>
        /// 更新Token过期时间,会先清除过期token
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public bool UpdateToken(string token)
        {
            //先清除过期token
            ClearExpireTokens();


            object target = null;
            lock (this)
            {
                target = tokenTable[token];
            }
            if (target == null) return false;

            (target as ConnectionToken).ExpireTime = NewExpireTime();
            return true;

        }


        /// <summary>
        /// 检查token是否合法，会首先清除过期token。token合法一并返回
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public (bool authorization, ConnectionToken connectionToken) CheckToken(string token)
        {
            //清空过期token
            ClearExpireTokens();


            lock (this)
            {
                bool hastoken = tokenTable.ContainsKey(token);
                if (hastoken)
                    return (true, tokenTable[token] as ConnectionToken);
                else
                    return (false, null);
            }
        }


        /// <summary>
        /// 移除token
        /// </summary>
        /// <param name="token"></param>
        public void RemoveToken(string token)
        {
            lock (this)
            {
                if (tokenTable.ContainsKey(token)) tokenTable.Remove(token);
            }
        }



        /// <summary>
        /// 清空过期Token
        /// </summary>
        public void ClearExpireTokens()
        {
            DateTime now = DateTime.Now;

            List<string> expKeys = new List<string>();

            lock (this)
            {
                foreach (string key in tokenTable.Keys)
                {
                    ConnectionToken ctk = tokenTable[key] as ConnectionToken;
                    if (now > ctk.ExpireTime)   //超时
                        expKeys.Add(key);
                }

                foreach (var key in expKeys)
                {
                    tokenTable.Remove(key);
                }
            }
        }



        /// <summary>
        /// 创建新uuid
        /// </summary>
        /// <param name="guidLens">使用的Guid长度个数，默认为1</param>
        /// <returns></returns>
        public static string NewUUID(int guidLens = 1)
        {
            string uuid = "";
            for (int i = 0; i < guidLens; i++)
            {
                uuid += Guid.NewGuid().ToString();
            }
            return uuid;
        }



        DateTime NewExpireTime()
        {
            return DateTime.Now.AddSeconds(expireSeconds);
        }


        /// <summary>
        /// 过期时间
        /// </summary>
        private int expireSeconds;


        /// <summary>
        /// 以token(string)为key
        /// </summary>
        private Hashtable tokenTable = new Hashtable();


        /// <summary>
        /// 使用的Guid长度个数,默认为1
        /// </summary>
        private int guidLens;
    }


    /// <summary>
    /// 连接Token
    /// </summary>
    public class ConnectionToken
    {
        /// <summary>
        /// UUID
        /// </summary>
        public string UUID { get; set; }

        /// <summary>
        /// 连接ID
        /// </summary>
        public long ID { get; set; }

        /// <summary>
        /// 过期时间
        /// </summary>
        public DateTime ExpireTime { get; set; }
    }
}
